package impl

import (
	"encoding/json"
	"fmt"
	_const "profile-manager/common/const"
	"profile-manager/common/util"
	"profile-manager/nodes/nodeif"

	"github.com/libujacob/jsone"
	log "github.com/sirupsen/logrus"
)

type Exporter struct {
	nodeif.Node
}

func (f *Exporter) ReadinessCheck(cfg *jsone.O) error {
	return nil
}

func (f *Exporter) RevertConfig(prfCfgType string, prfCfg *jsone.A, cfg *jsone.O) error {
	return nil
}

func GetTypeByKey(cfg jsone.O) string {
	var result string = ""
	for _, k := range cfg.Keys() {
		if k == "type" {
			result, _ = cfg.GetString(k)
		}
	}
	return result
}

func (f *Exporter) ApplyConfig(prfCfgType string, prfCfg *jsone.A, cfgObj *jsone.O, config *jsone.O) error {

	hostUrl := ""
	for _, val := range *prfCfg {
		if GetTypeByKey(val.(jsone.O)) == "http" {
			for _, key := range (val.(jsone.O)).Keys() {
				if key == "hostUrl" {
					hostUrl, _ = (val.(jsone.O)).GetString(key)
				}
			}
		}
	}

	if prfCfgType == "north" {

		flag, err := isSognoProfile(config)
		if err != nil {
			log.Error("Exporter config failed", err)
			return err
		}

		if flag == "true" {
			return cfgSongoExp(hostUrl)
		}

		err = f.configBroker(hostUrl, config)
		if err != nil {
			log.Error("Exporter Config broker failed.", err)
			return err
		}

		err = f.configNodes(hostUrl, config)
		if err != nil {
			log.Error("Exporter Config Node failed.", err)
			return err
		}
	}

	return nil

}

func (f *Exporter) configBroker(hostUrl string, config *jsone.O) error {
	host, port, err := util.GetBrokerHostAndPort(config)
	if err != nil {
		log.Error(err, "Getting broker host or port failed.")
		return err
	}

	url := hostUrl + _const.ExporterMQPath
	data := fmt.Sprintf(_const.MQInfo, host, port)
	log.Infof("data : %s", data)

	_, err = util.SendConfigToNode(url, data, "POST")
	if err != nil {
		log.Error(err, "Adding MQ failed.")
		return err
	}

	log.Info("HTTP exporter MQ config success")
	return nil
}

type nodeInfo struct {
	NodeName string `json:"nodeName"`
	Topic    string `json:"topic"`
}

func (f *Exporter) configNodes(hostUrl string, config *jsone.O) error {

	nodeInfo, err := getNodeInfo(config)
	if err != nil {
		return err
	}

	if len(nodeInfo) == 0 {
		return nil
	}

	data, err := json.Marshal(nodeInfo)
	if err != nil {
		log.Error(err, "json marsh failid.")
	}

	url := hostUrl + _const.ExporterNodePath
	log.Infof("data : %s", nodeInfo)

	_, err = util.SendConfigToNode(url, string(data), "POST")
	if err != nil {
		log.Error(err, "Adding MQ failed.")
		return err
	}

	log.Info("HTTP exporter Node config success")
	return nil
}

func getNodeInfo(config *jsone.O) ([]nodeInfo, error) {
	var nodeInfos []nodeInfo

	configObj, err := config.GetObject("config")
	if err != nil {
		return nil, err
	}

	//fledge node
	for _, key := range configObj.Keys() {
		nodeObj, err := configObj.GetObject(key)
		if err != nil {
			return nil, err
		}

		north := util.GetDefaultByKey(&nodeObj, "north")
		if north != nil {
			topic := util.GetValuesByKey(north, "topic")
			var NodeInfo nodeInfo
			NodeInfo.NodeName = key
			NodeInfo.Topic = topic
			nodeInfos = append(nodeInfos, NodeInfo)
		}
	}

	return nodeInfos, nil
}

func isSognoProfile(config *jsone.O) (string, error) {
	configObj, err := config.GetObject("config")
	if err != nil {
		return "false", err
	}

	//songo node, skip exporter config
	for _, key := range configObj.Keys() {
		if key == "sogno" {
			return "true", nil
		}
	}

	return "false", nil
}

func cfgSongoExp(hostUrl string) error {

	url := hostUrl + _const.ExporterMQPath

	//config MQ info
	host := _const.SognoMQHOST
	port := _const.SognoMQPORT

	data := fmt.Sprintf(_const.MQInfo, host, port)
	log.Infof("data : %s", data)
	_, err := util.SendConfigToNode(url, data, "POST")
	if err != nil {
		log.Error(err, "Adding MQ failed.")
		return err
	}

	log.Info("HTTP exporterMQ config success")

	//config sogno Nodes
	var nodeInfos [2]nodeInfo
	nodeInfos[0].NodeName = "fledge"
	nodeInfos[0].Topic = "/dpsim-powerflow"
	nodeInfos[1].NodeName = "sogno"
	nodeInfos[1].Topic = "/se"

	nodeData, err := json.Marshal(nodeInfos)
	if err != nil {
		log.Error(err, "json marsh failed.")
	}

	nodeUrl := hostUrl + _const.ExporterNodePath
	log.Infof("data : %s", nodeInfos)
	_, err = util.SendConfigToNode(nodeUrl, string(nodeData), "POST")
	if err != nil {
		log.Error(err, "Adding Node failed.")
		return err
	}

	log.Info("HTTP exporterMQ Node config success")

	return nil
}
